import 'package:common_utils/common_utils.dart';
import 'package:dio/dio.dart';
import 'package:x_core/net/base_entity.dart';

/// Created by XieXin on 2022/8/17.
/// 网络异常处理
/// 1xx：信息响应类，表示接收到请求并且继续处理
/// 2xx：处理成功响应类，表示动作被成功接收、理解和接受
/// 3xx：重定向响应类，为了完成指定的动作，必须接受进一步处理
/// 4xx：客户端错误，客户请求包含语法错误或者是不能正确执行
/// 5xx：服务端错误，服务器不能正确执行一个正确的请求
///
/// 100——客户必须继续发出请求
/// 101——客户要求服务器根据请求转换HTTP协议版本
/// 200——交易成功
/// 201——提示知道新文件的URL
/// 202——接受和处理、但处理未完成
/// 203——返回信息不确定或不完整
/// 204——请求收到，但返回信息为空
/// 205——服务器完成了请求，用户代理必须复位当前已经浏览过的文件
/// 206——服务器已经完成了部分用户的GET请求
/// 300——请求的资源可在多处得到
/// 301——删除请求数据
/// 302——在其他地址发现了请求数据
/// 303——建议客户访问其他URL或访问方式
/// 304——客户端已经执行了GET，但文件未变化
/// 305——请求的资源必须从服务器指定的地址得到
/// 306——前一版本HTTP中使用的代码，现行版本中不再使用
/// 307——申明请求的资源临时性删除
/// 400——错误请求，如语法错误
/// 401——请求授权失败
/// 402——保留有效ChargeTo头响应
/// 403——请求不允许
/// 404——没有发现文件、查询或URl
/// 405——用户在Request-Line字段定义的方法不允许
/// 406——根据用户发送的Accept拖，请求资源不可访问
/// 407——类似401，用户必须首先在代理服务器上得到授权
/// 408——客户端没有在用户指定的饿时间内完成请求
/// 409——对当前资源状态，请求不能完成
/// 410——服务器上不再有此资源且无进一步的参考地址
/// 411——服务器拒绝用户定义的Content-Length属性请求
/// 412——一个或多个请求头字段在当前请求中错误
/// 413——请求的资源大于服务器允许的大小
/// 414——请求的资源URL长于服务器允许的长度
/// 415——请求资源不支持请求项目格式
/// 416——请求中包含Range请求头字段，在当前请求资源范围内没有range指示值，请求也不包含If-Range请求头字段
/// 417——服务器不满足请求Expect头字段指定的期望值，如果是代理服务器，可能是下一级服务器不能满足请求
/// 500——服务器产生内部错误
/// 501——服务器不支持请求的函数
/// 502——服务器暂时不可用，有时是为了防止发生系统过载
/// 503——服务器过载或暂停维修
/// 504——网关超时，服务器使用另一个服务如tomcat或ftp来响应用户，解决方法：等待时间设定值加长比如10分钟，或优化后端程序。axios提示为request failed with statuscode 504
/// 505——服务器不支持或拒绝支请求头中指定的HTTP版本
class NetException implements Exception {
  ///成功
  static const int success = 200;
  static String successStr = "成功";

  ///请求收到，但返回信息为空
  static const int successNotContent = 204;
  static String successNotContentStr = "返回信息为空";

  ///请求语法错误
  static const int syntaxError = 400;
  static String syntaxErrorStr = "请求语法错误";

  ///请求授权失败
  static const int unauthorized = 401;
  static String unauthorizedStr = "请求没有权限";

  ///请求不允许
  static const int forbidden = 403;
  static String forbiddenStr = "服务器拒绝执行";

  ///无法连接服务器
  static const int notFound = 404;
  static String notFoundStr = "无法连接服务器";

  ///请求方法被禁止
  static const int requestForbid = 405;
  static String requestForbidStr = "请求方法被禁止";

  ///服务器内部错误
  static const internalServerError = 500;
  static String internalServerErrorStr = "服务器内部错误";

  ///无效的请求
  static const invalidRequest = 502;
  static String invalidRequestStr = "无效的请求";

  ///服务器挂了
  static const serverDown = 503;
  static String serverDownStr = "服务器异常";

  ///不支持HTTP协议请
  static const nonsupportHttp = 505;
  static String nonsupportHttpStr = "不支持HTTP协议请";

  //=========== ============================================================

  ///网络异常
  static const netException = 1000;
  static String netExceptionStr = "网络异常";

  ///解析异常
  static const parseException = 1001;
  static String parseExceptionStr = "解析异常";

  ///网络异常
  static const socketException = 1002;
  static String socketExceptionStr = "网络异常";

  ///服务器异常
  static const httpException = 1003;
  static String httpExceptionStr = "服务器异常";

  ///连接超时
  static const connectTimeoutException = 1004;
  static String connectTimeoutExceptionStr = "连接超时";

  ///请求超时
  static const requestTimeoutException = 1005;
  static String requestTimeoutExceptionStr = "请求超时";

  ///响应超时
  static const responseTimeoutException = 1006;
  static String responseTimeoutExceptionStr = "响应超时";

  ///取消请求
  static const cancelException = 1007;
  static String cancelExceptionStr = "取消请求";

  ///无网络
  static const notNetException = 1008;
  static String notNetExceptionStr = "无网络";

  ///数据异常
  static const dataException = 1009;
  static String dataExceptionStr = "数据异常";

  ///未知异常
  static const unknownException = -1;
  static String unknownExceptionStr = "未知错误";

  final String? message;
  final int? code;
  String? stackInfo;

  NetException([this.code, this.message]);

  factory NetException.fromDioError(DioError error) {
    switch (error.type) {
      case DioErrorType.cancel:
        return NetException(cancelException, cancelExceptionStr);
      case DioErrorType.connectionTimeout:
        return NetException(
            connectTimeoutException, connectTimeoutExceptionStr);
      case DioErrorType.sendTimeout:
        return NetException(
            requestTimeoutException, requestTimeoutExceptionStr);
      case DioErrorType.receiveTimeout:
        return NetException(
            responseTimeoutException, responseTimeoutExceptionStr);
      case DioErrorType.badResponse:
        try {
          /// http错误码带业务错误信息
          BaseEntity base = BaseEntity.fromJson(error.response?.data);
          if (base.code != null) {
            return NetException(base.code, base.message);
          }

          int? errCode = error.response?.statusCode;
          switch (errCode) {
            case syntaxError:
              return NetException(errCode!, syntaxErrorStr);
            case unauthorized:
              return NetException(errCode!, unauthorizedStr);
            case forbidden:
              return NetException(errCode!, forbiddenStr);
            case notFound:
              return NetException(errCode!, notFoundStr);
            case requestForbid:
              return NetException(errCode!, requestForbidStr);
            case internalServerError:
              return NetException(errCode!, internalServerErrorStr);
            case invalidRequest:
              return NetException(errCode!, invalidRequestStr);
            case serverDown:
              return NetException(errCode!, serverDownStr);
            case nonsupportHttp:
              return NetException(errCode!, nonsupportHttpStr);
            default:
              return NetException(errCode,
                  error.response?.statusMessage ?? unknownExceptionStr);
          }
        } on Exception catch (_) {
          return NetException(unknownException, unknownExceptionStr);
        }
      default:
        return NetException(unknownException, error.message);
    }
  }

  factory NetException.from(dynamic exception) {
    if (exception is DioError) {
      return NetException.fromDioError(exception);
    }
    if (exception is NetException) {
      return exception;
    } else {
      var apiException = NetException(unknownException, unknownExceptionStr);
      apiException.stackInfo = exception?.toString();
      return apiException;
    }
  }
}

/// 无网络错误
class NotNetError extends NetException {
  NotNetError()
      : super(NetException.notNetException, NetException.notNetExceptionStr);
}

/// 数据异常
class DataError extends NetException {
  DataError()
      : super(NetException.dataException, NetException.dataExceptionStr);
}

/// 解析异常
class JsonParseError extends NetException {
  JsonParseError()
      : super(NetException.parseException, NetException.parseExceptionStr);
}
